import fs from "fs";
import { scanApiFiles } from "./scan-api-files";
import path from "path";

export class ServerApiFile {
  dir: string;
  filePath: string;
  pathParts: string[];
  fileName: string;
  directory: string;
  name: string;
  ext: string;
  method: string;

  static fromDirectory(serverApiDir: string, relativePath = "") {
    const apiFiles = scanApiFiles(serverApiDir, relativePath);
    return apiFiles
      .filter(
        (filePath) =>
          filePath.endsWith(".get.ts") ||
          filePath.endsWith(".post.ts") ||
          filePath.endsWith(".put.ts") ||
          filePath.endsWith(".delete.ts")
      )
      .map((filePath) => new ServerApiFile(serverApiDir, filePath))
      // keep param route after explicit route, such as: `:id` after `update`
      .sort((a, b) => b.routePath.localeCompare(a.routePath));
  }

  constructor(dir: string, filePath: string) {
    this.dir = dir;
    this.filePath = filePath;
    this.pathParts = this.filePath.split("/");
    this.fileName = this.pathParts.at(-1) || "";
    this.directory = this.pathParts.slice(0, -1).join("/");

    const parts = this.fileName.split(".");
    this.name = parts.at(0) || "";
    this.ext = parts.at(-1) || "";
    this.method = parts.at(-2) || "get";
  }

  private _fileContent: string | null = null;
  get fileContent() {
    if (!this._fileContent) {
      this._fileContent = fs.readFileSync(
        path.join(this.dir, this.filePath),
        "utf-8"
      );
    }
    return this._fileContent;
  }

  // 生成路由路径, 例如: '/api/users/:id'
  get routePath() {
    return ['/api', ...this.pathParts.slice(0, -1), this.name]
      .map((part) => part.replace(/\[([^\]]+)\]/g, ":$1").toLowerCase())
      .join("/");
  }

  // 生成导入变量名，例如：user_id_get
  get importName() {
    return [...this.pathParts.slice(0, -1), this.name, this.method]
      .map((part) =>
        part
          .replace(/\[([^\]]+)\]/g, "$1")
          .replace(/\./g, "_")
          .replace(/-/g, "_")
          .toLowerCase()
      )
      .join("_");
  }

  get importPath() {
    return "@server/api/" + this.filePath.replace(".ts", "");
  }

  get isAsync() {
    return this.fileContent.includes("export default async function");
  }

  get hasBodySchema() {
    return this.fileContent.includes("export const bodySchema =");
  }

  get usesQuerySchema() {
    return this.fileContent.includes("export const querySchema =");
  }

  get usesResponse() {
    return (
      this.fileContent.includes("res: Response") ||
      this.fileContent.includes("response: Response")
    );
  }

  get usesRequestFiles() {
    return (
      this.fileContent.includes("request.files") ||
      this.fileContent.includes("request.file") ||
      this.fileContent.includes("res.files") ||
      this.fileContent.includes("res.file")
    );
  }

  get params() {
    return [...this.pathParts, this.name]
      .filter((part) => part.startsWith("[") && part.endsWith("]"))
      .map((part) => part.slice(1, -1));
  }
}
